#pragma once

#include "zen_game_object.h"
#include "zen_game_node.h"
#include "zen_matrix.h"
#include "zen_app.h"

namespace Zen
{
	namespace Game
	{

		class TouchDispatcher;

		class TouchHandle;

		struct TouchHandleStatus
		{
			std::shared_ptr<TouchHandle> handle;
			std::weak_ptr<Node> target;
			int priority{};
			bool acceptMultiTouch{};
		};

		/// <summary>
		/// Get default ActionDispatcher from Activity.
		/// </summary>
		class TouchDispatcher
		{
		public:
			void AddTouchHandle(std::shared_ptr<TouchHandle> handle, int priority, std::shared_ptr<Node> target, bool acceptMultiTouch);

			void RemoveTouchHandle(std::shared_ptr<TouchHandle> handle);

			void RemoveTouchHandleOnNode(std::shared_ptr<Node> attach);

			void RemoveAllTouchHandles();

			auto GetTouches() -> std::map<uint32_t, AppTouch> const&;

			void OnTouchDown(AppTouch const& touch);

			void OnTouchMove(AppTouch const& touch);

			void OnTouchUp(AppTouch const& touch);

			void OnTouchCancel(AppTouch const& touch);

			void ClearPriorityDirty();

		protected:
			friend class TouchDispatcher;

			void SetPriorityDirty();
			std::map<uint32_t /*AppTouch::no*/, AppTouch> mTouches;
			uint32_t mMainTouch{};
			std::vector<std::shared_ptr<TouchHandleStatus>> mTouchHandles;
			std::shared_ptr<TouchHandleStatus> mAct = nullptr;
			bool mIsHandlePriorityDirty = false;
		};

		class TouchHandle : public Object
		{
		public:
			virtual bool OnTouchDown(AppTouch const& touch)
			{
				return true;
			}

			virtual bool OnTouchMove(AppTouch const& touch)
			{
				return true;
			}

			virtual bool OnTouchUp(AppTouch const& touch)
			{
				return true;
			}

			virtual bool OnTouchCancel(AppTouch const& touch)
			{
				return true;
			}

			void SetEnabled(bool v);

			bool IsEnabled();

			void Release();

			void SetMultiTouch(bool v);

			bool IsMultiTouch();

		protected:
			bool mMultiTouch = false;
			bool mIsEnabled = true;
		};

		class DefaultTouchHandle : public TouchHandle
		{
		public:
			virtual bool OnTouchDown(AppTouch const& touch)
			{
				if (mCallbacks[0]) return mCallbacks[0](touch);
				return false;
			}

			virtual bool OnTouchMove(AppTouch const& touch)
			{
				if (mCallbacks[1]) return mCallbacks[1](touch);
				return false;
			}

			virtual bool OnTouchUp(AppTouch const& touch)
			{
				if (mCallbacks[2]) return mCallbacks[2](touch);
				return false;
			}

			virtual bool OnTouchCancel(AppTouch const& touch)
			{
				if (mCallbacks[3]) return mCallbacks[3](touch);
				if (mCallbacks[2]) return mCallbacks[2](touch);
				return false;
			}
			std::function<bool(AppTouch const&)>& TouchDownCallback()
			{
				return mCallbacks[0];
			}
			std::function<bool(AppTouch const&)>& TouchMoveCallback()
			{
				return mCallbacks[1];
			}
			std::function<bool(AppTouch const&)>& TouchUpCallback()
			{
				return mCallbacks[2];
			}
			std::function<bool(AppTouch const&)>& TouchCancelCallback()
			{
				return mCallbacks[3];
			}

		protected:
			std::function<bool(AppTouch const&)> mCallbacks[4];
		};

	} // namespace Game
} // namespace Zen
